# 正则表达式
# 正则表达式是一种用来匹配字符串的强有力的武器。它的设计思想是用一种描述性的语言来给字符串定义一个规则，
# 凡是符合规则的字符串，我们就认为它“匹配”了，否则，该字符串就是不合法的。
# 1. 如果直接给出字符，就是精确匹配
# 2. \d可以匹配一个数字，
# 3. \w可以匹配一个字母或数字
# 4. .可以匹配任意字符
# 5. *表示任意个字符（包括0个
# 6. +表示至少一个字符
# 7. ?表示0个或1个字符
# 8. {n}表示n个字符
# 9. {n,m}表示n-m个字符
# 10. \s可以匹配一个空格（也包括Tab等空白符）
# 11. 由于'-'是特殊字符，在正则表达式中，要用'\'转义 \-
# 例如：\d{3}\s+\d{3,8}可以匹配以任意个空格隔开的带区号的电话号码

# 进阶
# 要做更精确地匹配，可以用[]表示范围:
# [0-9a-zA-Z\_]可以匹配一个数字、字母或者下划线；
# [0-9a-zA-Z\_]+可以匹配至少由一个数字、字母或者下划线组成的字符串
# A|B可以匹配A或B，所以(P|p)ython可以匹配'Python'或者'python'
# ^表示行的开头，^\d表示必须以数字开头
# $表示行的结束，\d$表示必须以数字结束
# 例如:py也可以匹配'python'，但是加上^py$就变成了整行匹配，就只能匹配'py'了

# re模块
# Python提供re模块，包含所有正则表达式的功能。由于Python的字符串本身也用\转义，所以要特别注意：
s = 'ABC\\-001'  # Python的字符串
# 对应的正则表达式字符串变成：
# 'ABC\-001'
# 因此我们强烈建议使用Python的r前缀，就不用考虑转义的问题了：
s = r'ABC\-001'
# 判断正则表达式是否匹配: match()方法判断是否匹配，如果匹配成功，返回一个Match对象，否则返回None
import re

pattern = r'^\d{3}\-\d{3,8}$'
a = re.match(pattern, '010-12345')
print('a>>>', a)
b = re.match(pattern, '010 12345')
print('b>>>', b)
# 常见的判断方法就是
if re.match(pattern, '010-12345'):
    print('ok')
else:
    print('failed')

# 切分字符串
# 用正则表达式切分字符串比用固定的字符更灵活
# 1. 用固定的字符
print('a b c'.split(' '))
print('a   b c'.split(' '))
print('a,b c'.split(' '))
print('a,b;c'.split(' '))
# 2.正则
print(re.split(r'\s+', 'a b c'))
print(re.split(r'[\s\,\;\|]+', 'a,b;c d|e    f'))

# 分组
# 除了简单地判断是否匹配之外，正则表达式还有提取子串的强大功能。用()表示的就是要提取的分组
# 例如: ^(\d{3})-(\d{3,8})$分别定义了两个组，可以直接从匹配的字符串中提取出区号和本地号码：
pattern = r'^(\d{3})-(\d{3,8})$'
m = re.match(pattern, '010-12345')
print(m)
if m:
    print(m.group(0))
    print(m.group(1))
    print(m.group(2))
else:
    print('不匹配')
# 提取子串非常有用。来看一个更凶残的例子：
t = '19:05:30'
m = re.match(
    # 这个正则表达式可以直接识别合法的时间
    r'^(0[0-9]|1[0-9]|2[0-3]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$',
    t)
print(m.groups())

# 贪婪匹配
# 最后需要特别指出的是，正则匹配默认是贪婪匹配，也就是匹配尽可能多的字符
# 例如，匹配出数字后面的0：
print(re.match(r'^(\d+)(0*)$', '102300').groups())
# 由于\d+采用贪婪匹配，直接把后面的0全部匹配了，结果0*只能匹配空字符串了。
# 必须让\d+采用非贪婪匹配（也就是尽可能少匹配），才能把后面的0匹配出来，加个?就可以让\d+采用非贪婪匹配：
print(re.match(r'^(\d+?)(0*)$', '102300').groups())

# 编译
# 当我们在Python中使用正则表达式时，re模块内部会干两件事情：
# 1. 编译正则表达式，如果正则表达式的字符串本身不合法，会报错；
# 2. 用编译后的正则表达式去匹配字符串。
# 如果一个正则表达式要重复使用几千次，出于效率的考虑，我们可以预编译该正则表达式，
# 接下来重复使用时就不需要编译这个步骤了，直接匹配：
# 编译
re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$')
# 使用
print(re_telephone.match('010-12345').groups())
print(re_telephone.match('010-8086').groups())
